package security;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Class used to send and receive Messages over a TCP-Channel
 * @author Group 95
 */
public class TCPChannel implements Channel
{
    private static final Logger logger = Logger.getLogger("TCPChannel");
    
    private Socket tcpSocket;
    private BufferedReader bufferedReader;
    private PrintWriter out;
    private byte[] lastMessageRead;
    
    {
        logger.setLevel(Level.ALL);
    }
    
    public TCPChannel(final String serverHost,final int tcpPort) throws UnknownHostException, IOException
    {
        this(new Socket(serverHost,tcpPort));
        logger.log(Level.INFO, "TCPChannel serverHost: {0} ,tcpPort: {1}", new Object[]{serverHost, tcpPort});        
    }
    
    public TCPChannel(final Socket clientSocket) throws UnknownHostException, IOException
    {
        logger.log(Level.INFO, "TCPChannel clientSocket: {0}", new Object[]{clientSocket});
        tcpSocket=clientSocket;
        out=new PrintWriter(tcpSocket.getOutputStream(),true);
        bufferedReader= new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
    }
    
    public void setSocket(final Socket clientSocket) throws IOException
    {
        tcpSocket=clientSocket;
        out=new PrintWriter(tcpSocket.getOutputStream(),true);
        bufferedReader= new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
    }

    @Override
    public byte[] receiveMessage() throws IOException{
        String strLine=bufferedReader.readLine();
        if(strLine!=null)
        {
            byte[] bRet=strLine.getBytes();
            logger.log(Level.INFO, "receiveMessage() received String: {0}", new Object[]{strLine});
            logger.log(Level.INFO, "receiveMessage() received: {0}", new Object[]{bRet});
            lastMessageRead=bRet;
            return bRet;
        }
        return null;
    }

    @Override
    public byte[] reReceiveMessage() {
        logger.log(Level.INFO, "reReceiveMessage() lastMessageRead: {0}", new Object[]{lastMessageRead});
        return lastMessageRead;
    }
    
    @Override
    public void sendMessage(final byte[] bMessage) throws IOException{
        logger.log(Level.INFO, "sendMessage strMessage: {0}", new Object[]{bMessage});
        out.println(new String(bMessage));
        if(out.checkError())
        {
            throw new IOException("Having Trouble");
        }
    }

    @Override
    public void close() {
        logger.log(Level.INFO, "close()");
        try 
        {
            tcpSocket.close();
        }
        catch (IOException ex) 
        {
            logger.log(Level.SEVERE, null, ex);
        }
        try 
        {
            bufferedReader.close();
        } 
        catch (IOException ex) 
        {
            logger.log(Level.SEVERE, null, ex);
        }
        out.close();
    }
    
    /**
     * Checks if something is readable from the underlying socket
     * @return true if something can be read from the socket
     */
    public boolean receivable() throws IOException
    {
        return this.bufferedReader.ready();
    }    
}
